package cn.yujiago.api.alipay.util;

import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.TradeStatus;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradeQueryRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.model.result.AlipayF2FQueryResult;
import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 支付宝扫码支付工具类
 */
public class AlipayUtil {

    // 支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置，即扫码后回调地址
    // 注意：该地址得暴露在公网上才可被支付宝服务器回调成功
    // 提示：本地测试时可使用natapp进行内网穿透
    private static final String CALLBACK_URL = "http://m7u3jr.natappfree.cc/alipay_callback";

    static {
        // 一定要在创建AlipayTradeService之前设置参数
        Configs.init("zfbinfo.properties");
    }

    /**
     * 根据订单信息生成支付宝的二维码
     * @param outTradeNo    (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，需保证不重复
     * @param subject       (必填) 订单标题，粗略描述用户的支付目的。如“喜士多（浦东店）消费”
     * @param totalAmount   (必填) 订单总金额，单位为元，不能超过1亿元，【订单总金额】=【打折金额】+【不可打折金额】
     * @param undiscountableAmount  (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
     * @param sellerId  卖家支付宝账号ID，(打款到sellerId对应的支付宝账号)，如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
     * @param body      订单描述，如"购买商品2件共15.00元"
     * @param operatorId        商户操作员编号
     * @param storeId           (必填) 商户门店编号，如"test_store_id"
     * @param timeoutExpress    支付超时，如"120m"，定义为120分钟
     * @param goodsDetailList   商品明细列表
     * @return
     */
    public static AlipayF2FPrecreateResult generateQRCode(String outTradeNo,
                                                          String subject,
                                                          String totalAmount,
                                                          String undiscountableAmount,
                                                          String sellerId,
                                                          String body,
                                                          String operatorId,
                                                          String storeId,
                                                          String timeoutExpress,
                                                          List<GoodsDetail> goodsDetailList){

        AlipayTradeService tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();

        // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId("2088100200300400500");

        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(subject)
                .setTotalAmount(totalAmount)
                .setOutTradeNo(outTradeNo)
                .setUndiscountableAmount(undiscountableAmount)
                .setSellerId(sellerId)
                .setBody(body)
                .setOperatorId(operatorId)
                .setStoreId(storeId)
                .setExtendParams(extendParams)
                .setTimeoutExpress(timeoutExpress)
                // 支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置，即扫码后回调地址
                // 注意：该地址得暴露在公网上才可被支付宝服务器回调成功
                .setNotifyUrl(CALLBACK_URL)
                .setGoodsDetailList(goodsDetailList);

        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);

        return result;
    }

    /**
     * 根据订单号查询订单信息
     * @param outTradeNo
     * @return
     */
    public static AlipayF2FQueryResult query(String outTradeNo){

        AlipayTradeService tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();

        // (必填) 商户订单号，通过此商户订单号查询当面付的交易状态
        AlipayTradeQueryRequestBuilder builder = new AlipayTradeQueryRequestBuilder()
                .setOutTradeNo(outTradeNo);

        AlipayF2FQueryResult result = tradeService.queryTradeResult(builder);

        return result;
    }

    /**
     * 退款操作
     * @param outTradeNo    (必填) 外部订单号，需要退款交易的商户外部订单号
     * @param refundAmount  (必填) 退款金额，该金额必须小于等于订单的支付金额，单位为元
     * @param refundReason  (必填) 退款原因，可以说明用户退款原因，方便为商家后台提供统计
     * @param outRequestNo  (可选，需要支持重复退货时必填) 商户退款请求号，相同支付宝交易号下的不同退款请求号对应同一笔交易的不同退款申请，
     * @param storeId       (必填) 商户门店编号，退款情况下可以为商家后台提供退款权限判定和统计等作用，详询支付宝技术支持
     * @return
     */
    public static AlipayF2FRefundResult refund(String outTradeNo, String refundAmount, String refundReason, String outRequestNo, String storeId){

        AlipayTradeService tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();

        AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder()
                .setOutTradeNo(outTradeNo)
                .setRefundAmount(refundAmount)
                .setRefundReason(refundReason)
                .setOutRequestNo(outRequestNo)
                .setStoreId(storeId);

        AlipayF2FRefundResult result = tradeService.tradeRefund(builder);

        return result;
    }

    /**
     * 将回调返回的信息转化为Map
     * @param request
     * @return
     */
    public static Map<String, String> transferCallBackResultToMap(HttpServletRequest request){
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return params;
    }

    /**
     * 根据调用支付宝接口返回的状态进行相应的提示消息转换
     * @param status
     * @return
     */
    public static String checkStatus(TradeStatus status){

        switch (status) {
            case SUCCESS:
                return "支付宝操作成功: )";

            case FAILED:
                return "支付宝操作失败!!!";

            case UNKNOWN:
                return "系统异常，订单状态未知!!!";

            default:
                return "不支持的交易状态，交易返回异常!!!";
        }

    }

}
